package com.ibm.risk.irmp.gateway;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

@Slf4j
@Configuration
@ConditionalOnProperty(value = "app.irmp.gateway.sso.forward.enabled", havingValue = "true", matchIfMissing = true)
public class SSOFilter implements GlobalFilter, Ordered {
    public static final String AUTH_COOKIE_NAME = "Authorization";
    @Value("${app.irmp.common.auth.url.login}") String loginUrl;
    @Value("${app.irmp.common.auth.url.logout}") String logoutUrl;
    @Value("${app.irmp.common.auth.url.sso:}") String loginSsoUrl;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String requestUri = request.getURI().getPath();
        log.debug("requestUri: {}", requestUri);
        AbstractServerHttpResponse response = (AbstractServerHttpResponse)exchange.getResponse();
        if (requestUri.endsWith("/login-url")) {
            String url = loginUrl;
            if (loginUrl.indexOf("{redirect_uri}") > 0) {
                //e.g. http
                StringBuilder serviceRoot = getLoginSSOUrl(exchange);
                String path = request.getQueryParams().getFirst("path");
                if (path == null) {
                    path = "/";
                }
                String encodePath = URLEncoder.encode(path, StandardCharsets.UTF_8);
                encodePath = encodePath.replaceAll("%", "_pcts_");
                serviceRoot.append(")?path=").append(encodePath);
                log.debug("Service root: {}", serviceRoot);
                url = loginUrl.replace("{redirect_uri}", URLEncoder.encode(serviceRoot.toString(), StandardCharsets.UTF_8));
                log.debug("sso redirect to: {}", url);
            }
            response.setStatusCode(HttpStatus.OK);
            response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            DataBuffer buffer = response.bufferFactory().wrap(url.getBytes());
            return response.writeWith(Mono.just(buffer));
        }
        if (requestUri.endsWith("/logout")) {
            response.setStatusCode(HttpStatus.OK);
            response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            DataBuffer buffer = response.bufferFactory().wrap(logoutUrl.getBytes());
            exchange.getResponse().addCookie(ResponseCookie.from(AUTH_COOKIE_NAME, null).path("/")
                    .maxAge(0).build());
            chain.filter(exchange);
            return response.writeWith(Mono.just(buffer));
        }
        return chain.filter(exchange);
    }

    private StringBuilder getLoginSSOUrl(ServerWebExchange exchange) {
       if (StringUtils.isNotEmpty(loginSsoUrl)) {
           return new StringBuilder(loginSsoUrl);
       }
        ServerHttpRequest request = exchange.getRequest();
        String requestUrl = request.getURI().toString();
        String requestUri = request.getURI().getPath();
        log.debug("requestUrl: {}|", requestUrl);
        if (!requestUrl.endsWith(requestUri)) {
            requestUrl = requestUrl.substring(0, requestUrl.indexOf(requestUri) + requestUri.length());
        }
        StringBuilder serviceRoot = new StringBuilder(requestUrl);
        serviceRoot.delete(serviceRoot.indexOf("/login-url"), serviceRoot.length());
        serviceRoot.append("/login-sso");
        return serviceRoot;
    }
    @Override
    public int getOrder() {
        return 0;
    }
}
